package com.jgp.security.service;

import com.jgp.common.type.RoleType;
import com.jgp.common.utils.JGPUtil;
import com.jgp.security.annotation.Power;
import com.jgp.security.config.SecUserAdapter;
import com.jgp.security.props.SecurityConfigPropBean;
import com.jgp.security.secmodel.SecInstitution;
import com.jgp.security.secmodel.SecInstitutionUser;
import com.jgp.security.secmodel.SecUser;
import com.jgp.security.secrepository.SecUserRepository;
import com.jgp.sys.annotation.PowerGroup;
import com.jgp.sys.query.Operator;
import com.jgp.sys.query.OrderDirection;
import com.jgp.sys.query.OrderList;
import com.jgp.sys.query.QueryFilterList;
import com.jgp.sys.ui.Pager;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2019-11-02
 */
@PowerGroup("用户管理")
@Service
@Transactional(transactionManager = "secondTransactionManager",readOnly = true)
public class SecUserService {
    @Lazy
    @Autowired
    private SecUserRepository repository;
    
    @Autowired
    private SecUserAdapter userAdapter;
    
    @Autowired
    private SecurityConfigPropBean securityConfigPropBean;
    
    @Autowired
    private SecInstitutionService institutionService;
    
    private SecUser SUPER_ADMIN;
    
    @PostConstruct
    private void initSuperAdmin() {
        String superAdminInfo = securityConfigPropBean.getSuperAdmin();
        if (StringUtils.isNotBlank(securityConfigPropBean.getSuperAdmin())) {
            SUPER_ADMIN = new SecUser();
            SUPER_ADMIN.setId("bbd8a2fa40c6448d888bcf05b8715df4");
            SUPER_ADMIN.setRealName("超级管理员");
            SUPER_ADMIN.setLocked(false);
            SUPER_ADMIN.setDelFlag(false);
            String[] infos = superAdminInfo.split(",");
            SUPER_ADMIN.setUsername(infos[0]);
            if (infos.length == 1) {
                SUPER_ADMIN = operatorPwd(SUPER_ADMIN, "");
            } else if (infos.length == 2) {
                SUPER_ADMIN = operatorPwd(SUPER_ADMIN, infos[1]);
            }
        } else {
            SUPER_ADMIN = null;
        }
    }
    
    public SecUser getSuperAdmin() {
        return SUPER_ADMIN;
    }
    
    @Power(remark = "保持用户")
    @Transactional(transactionManager = "secondTransactionManager")
    public void saveSystemAdmin(SecUser user) {
        user.setType(RoleType.SYS_ADMIN);
        repository.createOrUpdate(user);
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public void saveSystemUser(SecUser user) {
        user.setType(RoleType.SYS_USER);
        repository.createOrUpdate(user);
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public SecUser saveUser(SecUser user) {
        return repository.createOrUpdate(user);
    }
    
    /**
     * 根据账号查询用户
     *
     * @param account 用户名、电话、邮箱
     * @return
     */
    public SecUser queryByAccount(String account) {
        SecUser user = null;
        if(StringUtils.isNotBlank(account)){
    
            if (account.equals(SUPER_ADMIN.getUsername())) {
                user = SUPER_ADMIN;
            } else {
                List<SecUser> users = repository.findByUsernameOrTelOrEmail(account, account, account);
                if(Objects.isNull(users)||users.size()==0) return null;
                user = users.stream().filter(u -> !u.getLocked() && !u.getDelFlag()).findFirst().get();
            }
            
        }
        
        return user;
    }
    
    public SecUser query(String id) {
        return repository.read(id);
    }
    
    public List<SecUser> query(List<String> ids) {
        return repository.read(ids);
    }
    
    public List<SecUser> querySystemAdmin(String realName, String username, String tel, String email,Boolean locked, Pager pager) {
        return query(null,realName, username, tel, email,locked, RoleType.SYS_ADMIN, pager);
    }
    
    public List<SecUser> querySystemUser(Long institutionId ,String realName, String username, String tel, String email,Boolean locked, Pager pager) {
        return query(institutionId,realName, username, tel, email,locked, RoleType.SYS_USER, pager);
    }
    
    public List<SecUser> query(Long institutionId,String realName, String username, String tel, String email,Boolean locked, RoleType type, Pager pager) {
        QueryFilterList filters = filters(realName, username, tel, email,locked, type);
        OrderList orders = new OrderList();
        orders.addOrder("createTimestamp", OrderDirection.DESC);
        if(Objects.nonNull(institutionId)){
            List<SecInstitution> institutions = Arrays.asList(new SecInstitution[]{institutionService.queryOne(institutionId)});
            List<SecInstitution> downs = institutionService.queryDown(institutions);
            downs.addAll(institutions);
            List<Long> ids = downs.stream().map(SecInstitution::getId).distinct().collect(Collectors.toList());
            return repository.read(filters, orders,(root, query, builder) -> {
                Subquery<SecInstitutionUser> subquery = query.subquery(SecInstitutionUser.class);
                Root<SecInstitutionUser> subRoot = subquery.from(SecInstitutionUser.class);
                subquery.select(subRoot);
                Predicate p = builder.equal(subRoot.get("userId"), root.get("id"));
                Predicate p2  =  subRoot.get("institutionId").in(ids);
                subquery.where(p,p2);
                return builder.and(builder.exists(subquery.where(p,p2)));
            },pager);
        }else {
            return repository.read(filters, orders,pager);
        }
        
    }
    
    private QueryFilterList filters(String realName, String username, String tel, String email,Boolean locked, RoleType type) {
        QueryFilterList filters = new QueryFilterList();
        if (StringUtils.isNotBlank(realName)) filters.addFilter("realName", Operator.like, realName);
        if (StringUtils.isNotBlank(username)) filters.addFilter("username", Operator.like, username);
        if (StringUtils.isNotBlank(tel)) filters.addFilter("tel", Operator.likeL, tel);
        if (StringUtils.isNotBlank(email)) filters.addFilter("email", Operator.like, email);
        if (Objects.nonNull(locked)) filters.addFilter("locked", Operator.eq, locked);
        if (Objects.nonNull(type)) filters.addFilter("type", Operator.eq, type);
        return filters;
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public void removeUser(List<String> ids) {
        QueryFilterList filters = new QueryFilterList();
        filters.addFilter("id", Operator.in, ids);
        // filters.addFilter("type", Operator.eq, RoleType.SYS_ADMIN);
        repository.delete(filters);
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public void lockUser(String id){
        SecUser user = repository.read(id);
        user.setLocked(true);
        repository.update(user);
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public SecUser setThirdOpenId(String userId,String thirdOpenId){
        SecUser user = repository.read(userId);
        user.setThirdOpenId(thirdOpenId);
        return repository.update(user);
    }
    
    public SecUser queryByThirdOpenId(String thirdOpenId) {
        QueryFilterList filters = new QueryFilterList();
        filters.addFilter("thirdOpenId",Operator.eq,thirdOpenId);
        repository.readOne(filters);
        return repository.readOne(filters);
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public void unLockUser(String id){
        SecUser user = repository.read(id);
        user.setLocked(false);
        repository.update(user);
    }
    
    /**
     * 系统重置密码
     *
     * @param id  用户ID
     * @param pwd 新密码
     */
    @Transactional(transactionManager = "secondTransactionManager")
    public void resetPassword(String id, String pwd) {
        SecUser user = repository.read(id);
        user = operatorPwd(user, pwd);
        repository.update(user);
    }
    
    public SecUser operatorPwd(SecUser user, String pwd) {
        String sugar = JGPUtil.randomStr(JGPUtil.random(3, 5));
        int encryptTime = JGPUtil.random(3, 5);
        user.setSugar(sugar);
        user.setEncryptTime(encryptTime);
        user.setPassword(userAdapter.encryptPwd(pwd, sugar, encryptTime));
        return user;
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public void lock(String userId) {
        SecUser user = repository.read(userId);
        user.setLocked(true);
        repository.update(user,"locked");
    }
    
    @Transactional(transactionManager = "secondTransactionManager")
    public void unLock(String userId) {
        SecUser user = repository.read(userId);
        user.setLocked(false);
        repository.update(user,"locked");
    }
}
